package org.yun.octopus.base.core;


import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.yun.octopus.base.annotation.Mark;
import javax.annotation.Resource;

import org.yun.octopus.base.enums.ResType;
import org.yun.octopus.base.enums.RoleType;
import org.yun.octopus.base.spi.IMarkCache;
import org.yun.octopus.base.util.CommonUtil;
import org.yun.octopus.base.util.ParamHelper;

import static org.yun.octopus.base.enums.CallType.SYNC_PART;
import static org.yun.octopus.base.enums.ResType.*;
import static org.yun.octopus.base.enums.RoleType.*;

/**
 * @author liyunfeng31
 */
@Aspect
@Component
public class MarkAspect {

    protected static final Logger LOG = LoggerFactory.getLogger(MarkAspect.class);

    @Resource
    private IMarkCache cache;

    @Resource
    private RollBackHandler rollBackHandler;


    @Pointcut("@annotation(org.yun.octopus.base.annotation.Mark)")
    public void markResult(){}

    /**
     * 处理完请求，返回内容
     * @param ret result
     */
    @AfterReturning(returning = "ret", pointcut = "markResult()")
    public void doAfterReturning(JoinPoint jp, Object ret) {
        doMark(jp,ret);
    }

    /**
     * 后置异常通知
     */
    @AfterThrowing(throwing = "ex", pointcut = "markResult()")
    public void throwsEx(JoinPoint jp, Throwable ex){
        System.out.println("### 后置异常通知"+ex);
        doMark(jp,ex);
    }


    /**
     * 打标
     * @param joinPoint jp
     * @param resp resp
     */
    private void doMark(JoinPoint joinPoint, Object resp) {
        MethodSignature sign = (MethodSignature)joinPoint.getSignature();
        Mark mark = sign.getMethod().getAnnotation(Mark.class);
        String group = mark.group();
        int stepNo = mark.stepNo();
        RoleType role = mark.role();
        Object[] args = joinPoint.getArgs();

        try {
            String bizNo = ParamHelper.getBizNo(args);
            String ctxBizNo = CommonUtil.getCtxBizNo(role, bizNo);
            System.out.println("method: "+sign.getMethod().getName()+",  stepNo:  "+stepNo+",  resp: "+JSON.toJSONString(resp));
            ResType type = ParamHelper.getResType(resp);
            if(type.equals(SUCCESS)){
                if(role == END){
                    System.out.println("ResultType success: will clear Mark "+type.code());
                    cache.clearMark(group, ctxBizNo);
                }else{
                    System.out.println("ResultType success: will save Mark "+type.code());
                    cache.save(group, ctxBizNo, stepNo, type.code(),bizNo);
                }
                return;
            }

            if(type.equals(UNKNOWN)){
                // 超时才记录本节点  直接错误不用打标
                System.out.println("ResultType: timeout, will saveMark"+type.code());
                cache.save(group, ctxBizNo, stepNo, type.code(),bizNo);
            }

            System.out.println("!!! ResultType:fail !!!  will fallback");
            rollBackHandler.execute(group, ctxBizNo, SYNC_PART.code());
        } catch (Exception e){
            LOG.error("mark result fail, group:{}, params:{}, stepNo:{}, resp:{} ", group,JSON.toJSONString(args),stepNo,resp,e);
        }
    }




}